#ifndef __CLIENT_H__
#define __CLIENT_H__

/**
 * @file client.h
 * @brief Client pour le serveur de fichier.
 * @author Florian.B
 * @version 0.1
 * @date 11 avril 2012
 *
 * Client pour le serveur de fichier. Il permet de télécharger un fichier à la fois sur un seul serveur.
 *
 */
#include <sys/time.h>
#include <pthread.h>
#include "../tools/list.h"
#include "../tools/toolsclientserver.h"
#include "../tools/toolsstring.h"
#include "../tools/pthreadlist.h"

typedef enum
  {
    CLIENT_SUCCESS /*!< Succès. */,
    CLIENT_ERROR /*!< Erreur indéterminé. */,
    CLIENT_SEND_ERROR /*!< Erreur lors de l'envoie d'une commande. */,
    CLIENT_SERVER_FAIL /*!< Le serveur ne reconnaît pas la commande. */,
    CLIENT_RECV_ERROR /*!< Problème lors de la réception. */,
    CLIENT_MALLOC_ERROR /*!< Si il y a un problème de mémoire. */,
    CLIENT_FREE_FAIL /*!< Le fichier à libérer n'existe pas sur le serveur. */,
    CLIENT_FILE_BUSY /*!< Le fichier est utilisé par un autre client. */,
    CLIENT_FILE_UNKNOW /*!< Le fichier n'existe pas sur le serveur. */,
    CLIENT_FILE_NULL /*!< Les fichiers passé en argument ne sont pas initialisé. */,
    CLIENT_HAVE /*!< Le client a déjà réceptionné la liste des fichiers. */,
    CLIENT_DONT_HAVE /*!< Le client n'a pas récupéré le liste de fichier du serveur. */
  }ClientReturn;

typedef struct {
  char *nom; /*!< Le nom du client. */
  char *host; /*!< Le server de connexion. */
  char *port; /*!< Le port de connexion. */
  int socket; /*!< La socket de connexion. -1 si pas de connexion. */
  List lFile; /*!< La liste des fichiers. */
  List lFileUse; /*!< La liste des fichiers utilisée, donc à libérer. */
  List lSocketFileDownload; /*!< La liste des sockets en cours de téléchargement. */  
  char haveLFile; /*!< Permet de déterminer si la liste de fichier à été récupérée. */
  int *socketPair; /*!< Utilisé quand interne, pour le téléchargement de fichier. */
  char *file; /*!< Utilisé qu'en interne, pour le téléchargment de fichier. Le fichier à télécharger. */
  char *fileDest; /*!< Utilisé aussi qu'en interne, c'est le fichier de destination. */
}Client;

/**
 * @brief Crée un client dans la mémoire.
 *
 * @param client Le client.
 * @param host Le domaine sur lequel se connecter.
 * @param port Le port de connexion.
 * @param nom Le nom de ce client.
 */
ClientReturn create_Client(Client **client, const char *host, const char *port, const char *nom);

/**
 * @brief Détruit un client de la mémoire.
 * 
 * @param client Le client.
 */
void delete_Client(Client **client);

/**
 *
 * @brief Copie un client dans un autre.
 *
 * @param clientA Le client qui sera un copy de clientB.
 * @param clientB Le client de référence.
 */
void createCopy_Client(Client **clientA, const Client *clientB);

/**
 * @brief Initialise le client.
 *
 * @param[in,out] client Le client à initialiser.
 * @param host Le domaine sur lequel se connecter.
 * @param port Le numéro de port de connexion.
 */
ClientReturn initialize_Client(Client *client, const char *host, const char *port, const char *nom);

/**
 * @brief Testament du client.
 * 
 * @param[in,out] client Le client à libérer.
 */
void testament_Client(Client *client);

/**
 * @brief Connexion au serveur.
 *
 * @param host Le nom ou l'adresse du serveur.
 * @param port Le port du serveur.
 * @return La socket de connexion entre le client et le serveur ou -1 en cas d'erreur.
 */
int connexion_Client(Client *client);

/**
 * @brief Réception du HELO. Le serveur envoie HELO lorsque un thread de service prend en charge le client.
 *
 * @param socket La socket de connexion.
 * @return CLIENT_SUCCESS si HELO à bien été récéptionné ou CLIENT_ERROR sinon. CLIENT_RECV_ERROR lors d'une erreur de réception.
 */
ClientReturn waitHello_Client(Client *client);

/**
 * @brief Place dans la liste les fichiers disponible sur le serveur.
 *
 * @param socket La socket de connexion.
 * @param[in,out] list La liste qui aura les différents fichiers.
 * @return CLIENT_SUCCESS si la liste est bien remplie. CLIENT_ERROR_SEND Si il y a un problème lors de l'envoie de la commande. CLIENT_SERVER_FAIL si le serveur ne connaît pas la commande.
 */
ClientReturn getListFile_Client(Client *client);

/**
 * @brief Enregistre le fichier demandé dans fileDest.
 *
 * @param socket La socket de connexion.
 * @param file Le fichier demander au serveur.
 * @param fileDest L'adresse du fichier de destination.
 * @param sockPair Un socket local permettant de mettre à jour la vitesse de téléchargement ainsi que le pourcentage téléchargé.
 */
ClientReturn getFile_Client(Client *client, const char *file, const char *fileDest, int *sockPair);

/**
 * @brief Libère le fichier sur le serveur.
 *
 * @param socket La socket de connexion.
 * @param file Le fichier à libérer.
 * @return CLIENT_SUCCESS si le serveur a bien libérer le fichier. CLIENT_SEND_ERROR si la commande n'a pas pu être envoyée. CLIENT_RECV_ERROR si un problème apparaît sur la réception. CLIENT_FREE_FAIL si le fichier n'a pas besoin d'être libèrer. CLIENT_ERROR si une erreur inconnue est apparue.
 */
ClientReturn freeFile_Client(Client *client, const char *file);

/**
 * @brief Ferme la connexion.
 *
 * @param socket La socket de connexion.
 * @return CLIENT_SUCCESS si la connexion à bien été fermé et CLIENT_SEND_ERR si il y a une erreur de transmission.
 */
ClientReturn quit_Client(Client *client);

/**
 * @brief Retourne une chaine de caractère qui devra être désallouer contenant le message d'erreur.
 *
 * @param cRet Le code de retour d'une fonction.
 * @return Une chaine de caractère signifiant l'erreur ou NULL si pas d'erreur.
 */
char *getMessageReturn_Client(ClientReturn cRet);

/**
 * @brief Envoie une commande et attend le retour de la commande (RCPT commande).
 *
 * @param socket La socket de connexion avec le serveur.
 * @param cmd La commande à envoyer.
 */
ClientReturn sendCommand_Client(const int socket, const char *cmd);

/**
 * @brief Récupère la liste de fichier
 *
 * @param client Le client qui possède la liste.
 */
List *getLFile_Client(Client *client);

/**
 * @brief Le client a t il déjà récupéré la liste de fichier.
 *
 * @param client Le client...
 * @return CLIENT_HAVE si oui et CLIENT_DONT_HAVE si non.
 */
ClientReturn isHaveList_Client(Client *client);

/**
 * @brief Récupère la liste de fichier
 *
 * @param client Le client qui possède la liste.
 */
List *getLFileUse_Client(Client *client);

/**
 * @brief Calcul de la vitesse de téléchargement.
 *
 * @param bytes Le nombre de bit.
 * @param msecs Le temps lors de la réception.
 * @return La valeur avec le taux.
 */
char *calc_speed(int bytes, double msecs, int pad);

#endif
